const axios = require('axios');
const Caregiver = require('../models/Caregiver');
const AppError = require('./appError');

/**
 * 地理位置服务类
 * 提供地址解析、距离计算、护理员匹配等功能
 */
class LocationService {
  constructor() {
    // 高德地图API配置
    this.amapApiKey = process.env.AMAP_API_KEY;
    this.amapBaseUrl = 'https://restapi.amap.com/v3';
    
    // 百度地图API配置（备用）
    this.baiduApiKey = process.env.BAIDU_API_KEY;
    this.baiduBaseUrl = 'https://api.map.baidu.com';
  }

  /**
   * 地址解析为坐标
   * @param {string} address - 地址字符串
   * @param {string} city - 城市名称
   * @returns {Promise<{lng: number, lat: number, formattedAddress: string}>}
   */
  async geocodeAddress(address, city = '') {
    try {
      // 使用高德地图API进行地址解析
      const response = await axios.get(`${this.amapBaseUrl}/geocode/geo`, {
        params: {
          key: this.amapApiKey,
          address: `${city}${address}`,
          output: 'json'
        },
        timeout: 5000
      });

      if (response.data.status === '1' && response.data.geocodes.length > 0) {
        const geocode = response.data.geocodes[0];
        const [lng, lat] = geocode.location.split(',').map(Number);
        
        return {
          lng,
          lat,
          formattedAddress: geocode.formatted_address,
          confidence: geocode.level
        };
      }
      
      throw new Error('地址解析失败');
    } catch (error) {
      console.error('地址解析错误:', error.message);
      throw new AppError('地址解析失败，请检查地址是否正确', 400);
    }
  }

  /**
   * 坐标反解析为地址
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @returns {Promise<{address: string, city: string, district: string}>}
   */
  async reverseGeocode(lng, lat) {
    try {
      const response = await axios.get(`${this.amapBaseUrl}/geocode/regeo`, {
        params: {
          key: this.amapApiKey,
          location: `${lng},${lat}`,
          output: 'json',
          radius: 1000,
          extensions: 'base'
        },
        timeout: 5000
      });

      if (response.data.status === '1' && response.data.regeocode) {
        const regeocode = response.data.regeocode;
        const addressComponent = regeocode.addressComponent;
        
        return {
          address: regeocode.formatted_address,
          city: addressComponent.city || addressComponent.province,
          district: addressComponent.district,
          street: addressComponent.streetNumber?.street || '',
          number: addressComponent.streetNumber?.number || ''
        };
      }
      
      throw new Error('坐标反解析失败');
    } catch (error) {
      console.error('坐标反解析错误:', error.message);
      throw new AppError('坐标反解析失败', 400);
    }
  }

  /**
   * 计算两点之间的距离（使用Haversine公式）
   * @param {number} lng1 - 点1经度
   * @param {number} lat1 - 点1纬度
   * @param {number} lng2 - 点2经度
   * @param {number} lat2 - 点2纬度
   * @returns {number} 距离（公里）
   */
  calculateDistance(lng1, lat1, lng2, lat2) {
    const R = 6371; // 地球半径（公里）
    const dLat = this.toRadians(lat2 - lat1);
    const dLng = this.toRadians(lng2 - lng1);
    
    const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
              Math.cos(this.toRadians(lat1)) * Math.cos(this.toRadians(lat2)) *
              Math.sin(dLng / 2) * Math.sin(dLng / 2);
    
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    const distance = R * c;
    
    return Math.round(distance * 100) / 100; // 保留两位小数
  }

  /**
   * 角度转弧度
   * @param {number} degrees - 角度
   * @returns {number} 弧度
   */
  toRadians(degrees) {
    return degrees * (Math.PI / 180);
  }

  /**
   * 获取路线规划和预估时间
   * @param {number} originLng - 起点经度
   * @param {number} originLat - 起点纬度
   * @param {number} destLng - 终点经度
   * @param {number} destLat - 终点纬度
   * @param {string} strategy - 路线策略 (0:速度优先, 1:费用优先, 2:距离优先, 3:不走高速)
   * @returns {Promise<{distance: number, duration: number, route: Array}>}
   */
  async getRouteInfo(originLng, originLat, destLng, destLat, strategy = '0') {
    try {
      const response = await axios.get(`${this.amapBaseUrl}/direction/driving`, {
        params: {
          key: this.amapApiKey,
          origin: `${originLng},${originLat}`,
          destination: `${destLng},${destLat}`,
          strategy,
          output: 'json'
        },
        timeout: 10000
      });

      if (response.data.status === '1' && response.data.route?.paths?.length > 0) {
        const path = response.data.route.paths[0];
        
        return {
          distance: Math.round(path.distance / 1000 * 100) / 100, // 转换为公里并保留两位小数
          duration: Math.round(path.duration / 60), // 转换为分钟
          tolls: path.tolls || 0, // 过路费
          traffic: path.traffic_lights || 0, // 红绿灯数量
          route: path.steps?.map(step => ({
            instruction: step.instruction,
            distance: step.distance,
            duration: step.duration
          })) || []
        };
      }
      
      throw new Error('路线规划失败');
    } catch (error) {
      console.error('路线规划错误:', error.message);
      // 如果API调用失败，使用直线距离估算
      const distance = this.calculateDistance(originLng, originLat, destLng, destLat);
      return {
        distance,
        duration: Math.round(distance * 3), // 估算：每公里3分钟
        tolls: 0,
        traffic: 0,
        route: [],
        estimated: true
      };
    }
  }

  /**
   * 查找附近的护理员
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @param {number} radius - 搜索半径（公里）
   * @param {Object} filters - 筛选条件
   * @returns {Promise<Array>} 护理员列表
   */
  async findNearbyCaregivers(lng, lat, radius = 10, filters = {}) {
    try {
      // 构建查询条件
      let query = {
        status: 'active',
        isVerified: true,
        'serviceArea.coordinates': {
          $near: {
            $geometry: {
              type: 'Point',
              coordinates: [lng, lat]
            },
            $maxDistance: radius * 1000 // 转换为米
          }
        }
      };

      // 应用筛选条件
      if (filters.skills && filters.skills.length > 0) {
        query.skills = { $in: filters.skills };
      }

      if (filters.minRating) {
        query['stats.averageRating'] = { $gte: filters.minRating };
      }

      if (filters.maxPrice) {
        query['pricing.baseRate'] = { $lte: filters.maxPrice };
      }

      if (filters.emergencyService) {
        query['availability.acceptsEmergency'] = true;
      }

      if (filters.overnightCare) {
        query['availability.acceptsOvernight'] = true;
      }

      // 查询护理员
      const caregivers = await Caregiver.find(query)
        .populate('user', 'name avatar phone')
        .select('user skills pricing stats serviceArea availability')
        .limit(50);

      // 计算距离并排序
      const caregiversWithDistance = caregivers.map(caregiver => {
        const [caregiverLng, caregiverLat] = caregiver.serviceArea.coordinates;
        const distance = this.calculateDistance(lng, lat, caregiverLng, caregiverLat);
        
        return {
          ...caregiver.toObject(),
          distance,
          matchScore: this.calculateMatchScore(caregiver, filters, distance)
        };
      });

      // 按匹配分数排序
      return caregiversWithDistance.sort((a, b) => b.matchScore - a.matchScore);
    } catch (error) {
      console.error('查找附近护理员错误:', error.message);
      throw new AppError('查找护理员失败', 500);
    }
  }

  /**
   * 计算护理员匹配分数
   * @param {Object} caregiver - 护理员信息
   * @param {Object} filters - 筛选条件
   * @param {number} distance - 距离
   * @returns {number} 匹配分数（0-100）
   */
  calculateMatchScore(caregiver, filters, distance) {
    let score = 0;
    
    // 距离分数（40%权重）- 距离越近分数越高
    const maxDistance = 20; // 最大考虑距离20公里
    const distanceScore = Math.max(0, (maxDistance - distance) / maxDistance * 40);
    score += distanceScore;
    
    // 评分分数（25%权重）
    const ratingScore = (caregiver.stats.averageRating || 0) / 5 * 25;
    score += ratingScore;
    
    // 经验分数（15%权重）
    const experienceScore = Math.min(caregiver.experience / 5, 1) * 15;
    score += experienceScore;
    
    // 订单完成数分数（10%权重）
    const orderScore = Math.min(caregiver.stats.totalOrders / 100, 1) * 10;
    score += orderScore;
    
    // 技能匹配分数（10%权重）
    if (filters.skills && filters.skills.length > 0) {
      const matchedSkills = filters.skills.filter(skill => 
        caregiver.skills.includes(skill)
      ).length;
      const skillScore = (matchedSkills / filters.skills.length) * 10;
      score += skillScore;
    } else {
      score += 10; // 如果没有特定技能要求，给满分
    }
    
    return Math.round(score * 100) / 100;
  }

  /**
   * 智能推荐护理员
   * @param {Object} orderInfo - 订单信息
   * @returns {Promise<Array>} 推荐的护理员列表
   */
  async recommendCaregivers(orderInfo) {
    const {
      location,
      pets,
      serviceType,
      startDateTime,
      endDateTime,
      isEmergency = false,
      budget
    } = orderInfo;

    try {
      // 解析地址获取坐标
      let coordinates;
      if (location.coordinates) {
        coordinates = location.coordinates;
      } else {
        const geocoded = await this.geocodeAddress(location.address, location.city);
        coordinates = [geocoded.lng, geocoded.lat];
      }

      // 根据宠物类型确定所需技能
      const requiredSkills = pets.map(pet => `${pet.species}_care`);
      
      // 构建筛选条件
      const filters = {
        skills: requiredSkills,
        emergencyService: isEmergency,
        maxPrice: budget
      };

      // 查找附近的护理员
      const nearbyCaregivers = await this.findNearbyCaregivers(
        coordinates[0],
        coordinates[1],
        15, // 15公里范围
        filters
      );

      // 进一步筛选可用的护理员
      const availableCaregivers = [];
      
      for (const caregiver of nearbyCaregivers) {
        // 检查时间可用性
        const isAvailable = await this.checkCaregiverAvailability(
          caregiver._id,
          new Date(startDateTime),
          new Date(endDateTime)
        );
        
        if (isAvailable) {
          // 计算预估到达时间
          const routeInfo = await this.getRouteInfo(
            caregiver.serviceArea.coordinates[0],
            caregiver.serviceArea.coordinates[1],
            coordinates[0],
            coordinates[1]
          );
          
          availableCaregivers.push({
            ...caregiver,
            estimatedArrival: routeInfo.duration,
            routeDistance: routeInfo.distance
          });
        }
      }

      // 返回前10个最佳匹配
      return availableCaregivers.slice(0, 10);
    } catch (error) {
      console.error('推荐护理员错误:', error.message);
      throw new AppError('推荐护理员失败', 500);
    }
  }

  /**
   * 检查护理员时间可用性
   * @param {string} caregiverId - 护理员ID
   * @param {Date} startDate - 开始时间
   * @param {Date} endDate - 结束时间
   * @returns {Promise<boolean>} 是否可用
   */
  async checkCaregiverAvailability(caregiverId, startDate, endDate) {
    try {
      const caregiver = await Caregiver.findById(caregiverId);
      if (!caregiver) return false;
      
      return await caregiver.checkAvailability(startDate, endDate);
    } catch (error) {
      console.error('检查护理员可用性错误:', error.message);
      return false;
    }
  }

  /**
   * 获取城市列表
   * @returns {Promise<Array>} 支持的城市列表
   */
  async getSupportedCities() {
    try {
      // 从数据库中获取有护理员的城市
      const cities = await Caregiver.aggregate([
        { $match: { status: 'active' } },
        {
          $group: {
            _id: '$serviceArea.city',
            caregiverCount: { $sum: 1 },
            averageRating: { $avg: '$stats.averageRating' }
          }
        },
        { $sort: { caregiverCount: -1 } }
      ]);

      return cities.map(city => ({
        name: city._id,
        caregiverCount: city.caregiverCount,
        averageRating: Math.round(city.averageRating * 10) / 10
      }));
    } catch (error) {
      console.error('获取城市列表错误:', error.message);
      throw new AppError('获取城市列表失败', 500);
    }
  }

  /**
   * 验证地址有效性
   * @param {string} address - 地址
   * @param {string} city - 城市
   * @returns {Promise<boolean>} 地址是否有效
   */
  async validateAddress(address, city) {
    try {
      const result = await this.geocodeAddress(address, city);
      return result.confidence && result.confidence !== 'Unknown';
    } catch (error) {
      return false;
    }
  }
}

module.exports = new LocationService();